/**
  ******************************************************************************
  * @file    main.c 
  * @brief   This example describes how to use the expanded IO (PCF8574) to 
             control LED on or off.
  * @date    2023-02-07
  * Copyright (c) 2023 Witmem Technology Co., Ltd
  * All rights reserved.
  *
  ******************************************************************************
  */

#include "main.h"

/* PCF8574 addr ranges from 0x20~0x27, 7 bit addr format: 0 1 0 0 A2 A1 A0 */
#define PCF8574_ADDR (0x27)

#define PCF8574_P0 (0)
#define PCF8574_P1 (1)
#define PCF8574_P2 (2)
#define PCF8574_P3 (3)
#define PCF8574_P4 (4)
#define PCF8574_P5 (5)
#define PCF8574_P6 (6)
#define PCF8574_P7 (7)

static void system_clock_init(void);
static void led_ctl(uint8_t ledx, uint8_t sta);
static void i2c_config(void);
static void key_config(void);
static void key_action(void);
static void pcf8574_config(void);
static void uart_init(void);

void main(void)
{
    printf_output_redirect_set(PRINTF_RETARGET_NONE);

    /* Reset all peripherals except PMU */
    RCC_Peri_Rst(0xFFFFFFFF & (~(RCC_PMU_PRSTN | RCC_GPIO_RSTN)));

    /* Enable N307 Interrupt */
    __enable_irq();
    __enable_mcycle_counter();
  
    printf_output_redirect_set(PRINTF_RETARGET_SEGGER);

    /* Initial Basic System: OSC and GPIO */
    system_clock_init();

    /* Initial periphral */
    uart_init();
    printf_output_redirect_set(PRINTF_RETARGET_UART0);
    i2c_config();
    key_config();
    pcf8574_config();

    /* Show message */
    printf("BUILD: %s %s\r\n", __DATE__, __TIME__);
    system_config_dump();

    /* Application entry */
    
    while(1)
    {
        key_action();
    }
}

static void system_clock_init(void)
{
    int ret = 0; 
    /* The clock instance */
    Hal_Clock_InitTypeDef* hal_clock_instance = hal_clock_instance_get();
    Hal_Clock_24mosc_Configuration hal_clock_24mosc_Configuration;

    /* Construct 24mosc related configuration parameters */
    hal_clock_24mosc_Configuration.use_24mosc_way = HAL_CLOCK_24MOSC_INTERNAL;
    hal_clock_24mosc_Configuration.clock_hz = 24576000;
    hal_clock_24mosc_Configuration.clock_divider = 1;
    hal_clock_24mosc_Configuration.internal_24mosc_calibration_flag = ENABLE;
    hal_clock_24mosc_Configuration.calibration_way = HAL_CLOCK_24MOSC_USE_32KOSC_CALIBRATION_PARAMETER;

    /*Initialize the clock instance.the system clock is from internal 24mosc.the 24mosc is calibrated by the xtal 32k*/
    ret = hal_clock_init(hal_clock_instance,HAL_CLOCK_24MOSC,HAL_CLOCK_24MOSC,&hal_clock_24mosc_Configuration,0,1,1);
    if(ret <= 0)
    {
        printf("hal_clock_init error:%d\r\n", ret);
    }

    /* According to the clock instance, initialize the hardware */
    ret = hal_clock_open(hal_clock_instance);
    if(ret <= 0)
    {
        printf("hal_clock_init error:%d\r\n", ret);
    }
}

static void led_ctl(uint8_t ledx, uint8_t sta)
{
    I2C_Read_Cmd(I2C, 0);
    uint8_t data = I2C_Read_Data(I2C);
    if(sta == 0)
    {
        data &= ~(1<<ledx);
    }
    else
    {
        data |= 1<<ledx;
    }
    I2C_Write_Data(I2C, data | 0x02);
}

static void i2c_config(void)
{
    I2C_InitTypeDef I2C_InitStruct;
    GPIO_InitTypeDef GPIO_InitStructure;
  
    RCC_CLK_EN_Ctl(RCC_I2C_PCLKEN,ENABLE);
    
    GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPU;
    GPIO_InitStructure.Alternate = GPIO_AF4_I2C | GPIO_AF5_I2C;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    I2C_InitStruct.Mode = I2C_MODE_MASTER;
    I2C_InitStruct.Speed = I2C_SPEED_FAST;
    I2C_InitStruct.AddrMode = I2C_ADDR_7BITS_MASTER;
    I2C_InitStruct.Restart = I2C_RESTART_ENABLE;
    I2C_InitStruct.Address = PCF8574_ADDR;
    I2C_InitStruct.Rate = 100000;
    I2C_InitStruct.SpkLen = 1;
    I2C_Init(I2C,&I2C_InitStruct);
}

static void key_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_IT_InitTypeDef GPIO_IT_InitStructure;

    RCC_CLK_EN_Ctl(RCC_DB_CLKEN,ENABLE);

    /* init the PA3 pin with input_pull mode */
    GPIO_InitStructure.Pin = GPIO_PIN_3;
    GPIO_InitStructure.Alternate = GPIO_AF3_GPIO;
    GPIO_InitStructure.Mode = GPIO_MODE_INPU;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

}

static void pcf8574_config(void)
{
    I2C_Write_Data(I2C, 0xff);
}

static void key_action(void)
{
    /* delay function is used to eliminate key jitter */
    system_delay_ms(80);
    if(GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET)
    {
        system_delay_ms(80);
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET)
        {        
            /* count number of interrupt generated by the PCF8574 module */
            static uint8_t count = 0;
            count++;
            /* 1 key action, PCF8574 generate 2 interrupt signals. */
            if(count <= 2)
            {
                /* write 0 led on */
                led_ctl(PCF8574_P0, 0);
            }
            else
            {
                /* write 1 led off */
                led_ctl(PCF8574_P0, 1);
                if(count == 4) count = 0;
            }
        }
    }
}

static void uart_init(void)
{
    /*init uart*/
    UART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_CLK_EN_Ctl(RCC_UART0_CLKEN,ENABLE);
   
    /*the gpio16,gpio17*/
    GPIO_InitStructure.Pin = GPIO_PIN_16 | GPIO_PIN_17;
    GPIO_InitStructure.Alternate = GPIO_AF16_UART0 | GPIO_AF17_UART0;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
  
    USART_InitStructure.BaudRate = 9600;
    USART_InitStructure.Parity = UART_PARITY_NONE;
    USART_InitStructure.StopBits = UART_STOPBITS_1;
    USART_InitStructure.WordLength = UART_WORDLENGTH_8B;
    USART_InitStructure.Mode = UART_MODE_UART;
    USART_InitStructure.FIFOCtl = DISABLE;
    UART_Init(UART0, &USART_InitStructure);
}